package vm.baseapi;

import app.boot.BaseFunction;
import build.Bin.Function;
import build.Bin.Var;
import expression.MathExpression;
import expression.StringExpression;
import vm.runtime.NextVMRuntime;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.InputMismatchException;

public class API {
    public static String[] NativeMethodList = {
            "println",
            "printInt",
            "printLong",
            "printError",
            "shell",
            "listen_process",
            "out",
            "close_in",
            "close_out"
    };
    public static boolean IsNativeMethodCode(String code) {
        try {
            String function = code.substring(0,code.indexOf("(")).trim();
            String content = code.substring(code.indexOf("(")+1 , code.lastIndexOf(")")).trim();
            return new ArrayList<String>(Arrays.asList(API.NativeMethodList)).contains(function);
        }catch (Exception e) {
            return false;
        }
    }
    public static boolean IsNativeMethod(String function) {
        return new ArrayList<String>(Arrays.asList(API.NativeMethodList)).contains(function);
    }
    public static void run(String[] tokens , NextVMRuntime nextVMRuntime,String SourceCode) throws Exception {
        String Name = tokens[0];
        if (Name.equals("println")) {
            String Content = Var.joinElementsAfterIndex(tokens,1,",");
            Println.run(StringExpression.getExpression(Content , nextVMRuntime));
        }
        else if (Name.equals("printInt")) {
            String Content = tokens[1];
            double print = MathExpression.evaluateExpression(Content , nextVMRuntime);
            //System.out.println(print);
            Println.PrintInt((int) print);
        }
        else if (Name.equals("printLong")) {
            String Content = tokens[1];
            double print = MathExpression.evaluateExpression(Content , nextVMRuntime);
            //System.out.println(print);
            Println.PrintLong((long) print);
        }
        else if (Name.equals("printError")) {
            String Content = tokens[1];
            Println.PrintError(StringExpression.getExpression(Content , nextVMRuntime));
        }
        else if (Name.equals("shell")) {
            String Content = tokens[1];
            Shell.executeCommand(StringExpression.getExpression(Content , nextVMRuntime));
        }
        else if (Name.equals("listen_process")) {
            String exec = StringExpression.getExpression(tokens[1],nextVMRuntime);
            NextVMRuntime deal_fn = NextVMRuntime.getFunctionFromRuntime(tokens[2].trim() , nextVMRuntime);
            assert deal_fn != null;
            deal_fn.build();

            LocalProcessSocket localProcessSocket = new LocalProcessSocket();
            localProcessSocket.run(exec);

            OutputStream outputStream = localProcessSocket.getOutput();
            InputStream inputStream = localProcessSocket.getInput();
            int i = -1;
            deal_fn.LastRuntime = nextVMRuntime;
            byte[] bytes = new byte[1024];
            outputStream.write("hello world".getBytes());
            outputStream.flush();
            boolean a = true;
            while ((i = inputStream.read(bytes)) != -1) {
                try{
                    String pointer_1 = String.valueOf(BaseFunction.getRandomLong());
                    String pointer_2 = String.valueOf(BaseFunction.getRandomLong());
                    nextVMRuntime.values.put(pointer_1 , bytes);
                    nextVMRuntime.values.put(pointer_2 , outputStream);
                    String[] Input = {pointer_1 , pointer_2};
                    Function.putInputFunction(tokens[2].trim() , deal_fn , nextVMRuntime , Input);
                    nextVMRuntime.values.remove(pointer_1);
                    nextVMRuntime.values.remove(pointer_2);
                    deal_fn.run();
                }
                catch (Exception e){
                    break;
                }
            }
        }
        else if (Name.equals("out")) {
            //System.out.println(StringExpression.getValueFromNextVM(tokens[1].trim(),nextVMRuntime) instanceof byte[]);
            OutputStream outputStream = (OutputStream) StringExpression.getValueFromNextVM(tokens[1].trim(),nextVMRuntime);
            byte[] bytes = (byte[]) StringExpression.getValueFromNextVM(tokens[2].trim(),nextVMRuntime);

            assert outputStream != null;
            assert bytes != null;
            outputStream.write(bytes);
            outputStream.flush();
        }
        else if (Name.equals("close_in")) {
            InputStream inputStream = (InputStream) StringExpression.getValueFromNextVM(tokens[1].trim(),nextVMRuntime);
            assert inputStream != null;
            inputStream.close();
        }
        else if (Name.equals("close_out")) {
            OutputStream outputStream = (OutputStream) StringExpression.getValueFromNextVM(tokens[1].trim(),nextVMRuntime);
            assert outputStream != null;
            outputStream.close();
        }
        else {
            throw new Exception("Unknown Function: "+Name);
        }
    }
    // 将对象转换为字节数组的辅助方法
    public static byte[] convertToByteArray(Serializable obj) throws IOException {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            oos.writeObject(obj);
            oos.flush();
            return bos.toByteArray();
        }
    }
}
